/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef RTC_REG_ACCESS_H
#define RTC_REG_ACCESS_H

/*!
 * @file rtc_reg_access.h
 * @brief This file declares or defines rtc register access functions
 */

/*******Includes***************************************************************/
#include <stdbool.h>
#include "device_registers.h"
#include "rtc_drv.h"

/*******Definitions************************************************************/
/* Configuration */
#define RTC_CFG_COSEL(x)      (((uint32_t)(((uint32_t)(x)) << RTC_CFG_COSEL_Pos)) & RTC_CFG_COSEL_Msk)
#define RTC_CFG_COEN(x)       (((uint32_t)(((uint32_t)(x)) << RTC_CFG_COEN_Pos)) & RTC_CFG_COEN_Msk)
#define RTC_CFG_RTCEN(x)      (((uint32_t)(((uint32_t)(x)) << RTC_CFG_RTCEN_Pos)) & RTC_CFG_RTCEN_Msk)
#define RTC_CFG_ALMEN(x)      (((uint32_t)(((uint32_t)(x)) << RTC_CFG_ALMEN_Pos)) & RTC_CFG_ALMEN_Msk)
#define RTC_CFG_PALMEN(x)     (((uint32_t)(((uint32_t)(x)) << RTC_CFG_PALMEN_Pos)) & RTC_CFG_PALMEN_Msk)
#define RTC_CFG_TRIGEN(x)     (((uint32_t)(((uint32_t)(x)) << RTC_CFG_TRIGEN_Pos)) & RTC_CFG_TRIGEN_Msk)
#define RTC_CFG_CLKSEL(x)     (((uint32_t)(((uint32_t)(x)) << RTC_CFG_CLKSEL_Pos)) & RTC_CFG_CLKSEL_Msk)

/* Compensation */
#define RTC_ICOMP_COMP(x)     (((uint32_t)(((uint32_t)(uint8_t)(x)) << RTC_ICOMP_COMP_Pos)) & RTC_ICOMP_COMP_Msk)
#define RTC_ICOMP_INR(x)      (((uint32_t)(((uint32_t)(x)) << RTC_ICOMP_INR_Pos)) & RTC_ICOMP_INR_Msk)

/* Interupt enable */
#define RTC_INT_ALMIEN(x)     (((uint32_t)(((uint32_t)(x)) << RTC_INT_ALMIEN_Pos)) & RTC_INT_ALMIEN_Msk)
#define RTC_INT_PALMIEN(x)    (((uint32_t)(((uint32_t)(x)) << RTC_INT_PALMIEN_Pos)) & RTC_INT_PALMIEN_Msk)
#define RTC_INT_SCOFIEN(x)    (((uint32_t)(((uint32_t)(x)) << RTC_INT_SCOFIEN_Pos)) & RTC_INT_SCOFIEN_Msk)

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Config the RTC clock source
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] out: The clock source for the RTC
 * @return None
 */
static inline void RTC_REG_SelectClockSource(RTC_Type* regBase, rtc_clk_src_t src)
{
    uint32_t val = regBase->CFG;

    val &= ~(RTC_CFG_CLKSEL_Msk);
    val |= RTC_CFG_CLKSEL(src);
    regBase->CFG = val;
}

/*!
 * @brief Config the RTC clock out pin source
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] out: The source for the RTC clock out pin
 * @return None
 */
static inline void RTC_REG_SelectClockOutSource(RTC_Type* regBase, rtc_clk_out_t out)
{
    uint32_t val = regBase->CFG;

    val &= ~(RTC_CFG_COSEL_Msk);
    val |= RTC_CFG_COSEL(out);
    regBase->CFG = val;
}
/*!
 * @brief Open or close the RTC clock out
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Open or close the clock out
 *            - true: Open the clock out
 *            - false: Close the clock out
 * @return None
 */
static inline void RTC_REG_SetClockOutEnable(RTC_Type* regBase, bool enable)
{
    uint32_t val = regBase->CFG;

    val &= ~(RTC_CFG_COEN_Msk);
    val |= RTC_CFG_COEN(enable ? 1U : 0U);
    regBase->CFG = val;
}

/*!
 * @brief Enable or disable the RTC
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Enable or disable RTC
 *            - true: Enable RTC
 *            - false: Disable RTC
 * @return None
 */
void RTC_REG_SetRTCEnable(RTC_Type* regBase, bool enable);

/*!
 * @brief Check the state of RTC instance
 *
 * @param[in] regBase: The RTC register base address
 * @return true: RTC is enabled
 *         false: RTC is disabled
 */
static inline bool RTC_REG_IsRTCEnabled(RTC_Type* regBase)
{
    uint32_t val = regBase->CFG;

    val = (val & RTC_CFG_RTCEN_Msk) >> RTC_CFG_RTCEN_Pos;

    return (val == 1U) ? true : false;
}

/*!
 * @brief Enable or disable the RTC instance alarm
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Enable or disable the alarm
 *            - true: Enable the RTC alarm
 *            - false: Disable the RTC alarm
 * @return None
 */
static inline void RTC_REG_SetAlarmEnable(RTC_Type* regBase, bool enable)
{
    uint32_t val = regBase->CFG;

    val &= ~(RTC_CFG_ALMEN_Msk);
    val |= RTC_CFG_ALMEN(enable ? 1U : 0U);
    regBase->CFG = val;
}

/*!
 * @brief Enable or disable the RTC instance periodic alarm
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Enable or disable the periodic alarm
 *            - true: Enable the RTC periodic alarm
 *            - false: Disable the RTC periodic alarm
 * @return None
 */
static inline void RTC_REG_SetPeriodicAlarmEnable(RTC_Type* regBase, bool enable)
{
    uint32_t val = regBase->CFG;

    val &= ~(RTC_CFG_PALMEN_Msk);
    val |= RTC_CFG_PALMEN(enable ? 1U : 0U);
    regBase->CFG = val;
}

/*!
 * @brief Enable or disable the RTC instance trigger via ICM function
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Enable or disable the trigger via ICM function
 *            - true: Enable the RTC trigger via ICM function
 *            - false: Disable the RTC trigger via ICM function
 * @return None
 */
static inline void RTC_REG_SetTriggerEnable(RTC_Type* regBase, bool enable)
{
    uint32_t val = regBase->CFG;

    val &= ~(RTC_CFG_TRIGEN_Msk);
    val |= RTC_CFG_TRIGEN(enable ? 1U : 0U);
    regBase->CFG = val;
}

/*!
 * @brief Check the state of RTC instance trigger via ICM function
 *
 * @param[in] regBase: The RTC register base address
 * @return true: Trigger via ICM function is enabled
 *         false: Trigger via ICM function is disabled
 */
static inline bool RTC_REG_IsTriggerEnabled(const RTC_Type* regBase)
{
    uint32_t val = regBase->CFG;

    val = (val & RTC_CFG_TRIGEN_Msk) >> RTC_CFG_TRIGEN_Pos;

    return (val == 1U) ? true : false;
}

/*!
 * @brief Set the counter value of RTC instance, the counter can be only set when RTC is in disabled state
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] value: Counter value
 * @return ERR_SUCCESS: Set counter value successfully
 *         ERR_BUSY: Set counter failed
 */
errcode_t RTC_REG_SetCounterValue(RTC_Type* regBase, uint32_t value);

/*!
 * @brief Get the counter value of RTC instance
 *
 * @param[in] regBase: The RTC register base address
 * @return Current value of counter
 */
static inline uint32_t RTC_REG_GetCounterValue(const RTC_Type* regBase)
{
    uint32_t val = regBase->SCNT;

    val = (val & RTC_SCNT_SCNT_Msk) >> RTC_SCNT_SCNT_Pos;

    return val;
}

/*!
 * @brief Set the target time of RTC alarm
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] seconds: Target time of alarm
 * @return None
 */
static inline void RTC_REG_SetAlarmTarget(RTC_Type* regBase, uint32_t seconds)
{
    regBase->ALM = seconds;
}

/*!
 * @brief Get the current target time of RTC alarm
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] value: Target time of alarm
 * @return Current target time of RTC alarm
 */
static inline uint32_t RTC_REG_GetAlarmTarget(const RTC_Type* regBase)
{
    uint32_t val = regBase->ALM;

    val = (val & RTC_ALM_ALM_Msk) >> RTC_ALM_ALM_Pos;

    return val;
}

/*!
 * @brief Set the interval of RTC periodic alarm
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] interval: interval time of periodic alarm
 * @return None
 */
static inline void RTC_REG_SetPeriodicAlarmInterval(RTC_Type* regBase, uint32_t interval)
{
    regBase->PALM = interval;
}

/*!
 * @brief Get the current interval of RTC periodic alarm
 *
 * @param[in] regBase: The RTC register base address
 * @return Current interval of RTC periodic alarm
 */
static inline uint32_t RTC_REG_GetPeriodicAlarmInterval(const RTC_Type* regBase)
{
    uint32_t val = regBase->PALM;

    val = (val & RTC_PALM_PALM_Msk) >> RTC_PALM_PALM_Pos;

    return val;
}

/*!
 * @brief Set the prescaler vaule of RTC
 *
 * @param[in] regBase: The RTC register base address
 * @return ERR_SUCCESS: Set prescaler value successfully
 *         ERR_BUSY: Set prescaler failed
 */
errcode_t RTC_REG_SetPrescalerValue(RTC_Type* regBase, uint16_t value);

/*!
 * @brief Get the current value of RTC prescaler
 *
 * @param[in] regBase: The RTC register base address
 * @return Current value of RTC prescaler
 */
static inline uint16_t RTC_REG_GetPrescalerValue(const RTC_Type* regBase)
{
    uint32_t val = regBase->PSCAL;

    val = (val & RTC_PSCAL_PSCAL_Msk) >> RTC_PSCAL_PSCAL_Pos;

    return (uint16_t)val;
}

/*!
 * @brief Set the compensation of RTC instance
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] compensation: Compensation value
 * @param[in] interval: Compensation interval
 * @return None
 */
static inline void RTC_REG_SetCompensation(RTC_Type* regBase, int8_t compensation, uint8_t interval)
{
    uint32_t val = regBase->ICOMP;

    val &= ~(RTC_ICOMP_COMP_Msk);
    val &= ~(RTC_ICOMP_INR_Msk);
    val |= RTC_ICOMP_COMP(compensation);
    val |= RTC_ICOMP_INR(interval);
    regBase->ICOMP = val;
}

/*!
 * @brief Get the current compensation of RTC instance
 *
 * @param[in] regBase: The RTC register base address
 * @param[out] compensation: Current compensation value
 * @param[out] interval: Current compensation interval
 * @return None
 */
static inline void RTC_REG_GetCompensation(const RTC_Type* regBase, int8_t* compensation, uint8_t* interval)
{
    uint32_t val = regBase->ICOMP;

    *compensation = (int8_t)((val & RTC_ICOMP_COMP_Msk) >> RTC_ICOMP_COMP_Pos);
    *interval = (uint8_t)((val & RTC_ICOMP_INR_Msk) >> RTC_ICOMP_INR_Pos);
}

/*!
 * @brief Enable or disable the RTC alarm interrupt
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Enable or disable the RTC alarm interrupt
 *            - true: Enable the RTC RTC alarm interrupt
 *            - false: Disable the RTC RTC alarm interrupt
 * @return None
 */
static inline void RTC_REG_SetAlarmIntEnable(RTC_Type* regBase, bool enable)
{
    uint32_t val = regBase->INT;

    val &= ~(RTC_INT_ALMIEN_Msk);
    val |= RTC_INT_ALMIEN(enable ? 1U : 0U);
    regBase->INT = val;
}

/*!
 * @brief Enable or disable the RTC periodic alarm interrupt
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Enable or disable the RTC periodic alarm interrupt
 *            - true: Enable the RTC RTC periodic alarm interrupt
 *            - false: Disable the RTC RTC periodic alarm interrupt
 * @return None
 */
static inline void RTC_REG_SetPeriodicAlarmIntEnable(RTC_Type* regBase, bool enable)
{
    uint32_t val = regBase->INT;

    val &= ~(RTC_INT_PALMIEN_Msk);
    val |= RTC_INT_PALMIEN(enable ? 1U : 0U);
    regBase->INT = val;
}

/*!
 * @brief Enable or disable the RTC counter overflow interrupt
 *
 * @param[in] regBase: The RTC register base address
 * @param[in] enable: Enable or disable the RTC counter overflow interrupt
 *            - true: Enable the RTC RTC counter overflow interrupt
 *            - false: Disable the RTC RTC counter overflow interrupt
 * @return None
 */
static inline void RTC_REG_SetOverflowIntEnable(RTC_Type* regBase, bool enable)
{
    uint32_t val = regBase->INT;

    val &= ~(RTC_INT_SCOFIEN_Msk);
    val |= RTC_INT_SCOFIEN(enable ? 1U : 0U);
    regBase->INT = val;
}

/*!
 * @brief Check if the alarm event has occurred
 *
 * @param[in] regBase: The RTC register base address
 * @return true: The alarm event has occurred
 *         false: The alarm event has not occurred
 */
static inline bool RTC_REG_GetAlarmIntFlag(const RTC_Type* regBase)
{
    uint32_t val = regBase->STATUS;

    val = (val & RTC_STATUS_ALMF_Msk) >> RTC_STATUS_ALMF_Pos;

    return (val == 1U) ? true : false;
}

/*!
 * @brief Check if the periodic alarm event has occurred
 *
 * @param[in] regBase: The RTC register base address
 * @return true: The periodic alarm event has occurred
 *         false: The periodic alarm event has not occurred
 */
static inline bool RTC_REG_GetPeriodicAlarmIntFlag(const RTC_Type* regBase)
{
    uint32_t val = regBase->STATUS;

    val = (val & RTC_STATUS_PALMF_Msk) >> RTC_STATUS_PALMF_Pos;

    return (val == 1U) ? true : false;
}

/*!
 * @brief Check if the counter overflow event has occurred
 *
 * @param[in] regBase: The RTC register base address
 * @return true: The counter overflow event has occurred
 *         false: The counter overflow event has not occurred
 */
static inline bool RTC_REG_GetOverflowIntFlag(const RTC_Type* regBase)
{
    uint32_t val = regBase->STATUS;

    val = (val & RTC_STATUS_SCOFF_Msk) >> RTC_STATUS_SCOFF_Pos;

    return (val == 1U) ? true : false;
}

/*!
 * @brief Clear the alarm interrupt flag
 *
 * @param[in] regBase: The RTC register base address
 * @return None
 */
static inline void RTC_REG_ClearAlarmIntFlag(RTC_Type* regBase)
{
    uint32_t val = ((uint32_t)1U << RTC_STATUS_ALMF_Pos) & RTC_STATUS_ALMF_Msk;

    regBase->STATUS = val;
}

/*!
 * @brief Clear the periodic alarm interrupt flag
 *
 * @param[in] regBase: The RTC register base address
 * @return None
 */
static inline void RTC_REG_ClearPeriodicAlarmIntFlag(RTC_Type* regBase)
{
    uint32_t val = ((uint32_t)1U << RTC_STATUS_PALMF_Pos) & RTC_STATUS_PALMF_Msk;

    regBase->STATUS = val;
}

/*!
 * @brief Clear the overflow interrupt flag
 *
 * @param[in] regBase: The RTC register base address
 * @return None
 */
static inline void RTC_REG_ClearOverflowIntFlag(RTC_Type* regBase)
{
    uint32_t val = ((uint32_t)1U << RTC_STATUS_SCOFF_Pos) & RTC_STATUS_SCOFF_Msk;

    regBase->STATUS = val;
}

#if defined(__cplusplus)
}
#endif

#endif /* RTC_REG_ACCESS_H */

/*******EOF********************************************************************/
